#include<iostream>
#include<string>
#include<memory>
using namespace std;
//工厂模式:

//定义一个抽象类提供方法
class Fruit
{
public:
    virtual void name()=0;

};

//定义派生类继承基类并重写虚函数
class Banana:public Fruit
{
public:
    void name() override
    {
        std::cout<<"我是一个Bnana"<<std::endl;
    }
};

class Apple:public Fruit
{
public:
    void name() override
    {
        std::cout<<"我是一个Apple哈哈哈"<<std::endl;
    }
};


class Animal
{
public:
    virtual void name()=0;

};

//定义派生类继承基类并重写虚函数
class Lamp:public Animal
{
public:
    void name() override
    {
        std::cout<<"我是一只山羊"<<std::endl;
    }
};

class Dog:public Animal
{
public:
    void name() override
    {
        std::cout<<"我是一跳dog"<<std::endl;
    }
};
// 这样写每次多一个产品就要添加一种方法
// //定义一个工厂类提供静态方法来生产产品
// class FruitFactoy
// {
// public:
//     //返回基类的共享指针来调用派生类的重写的虚函数
//     static std::shared_ptr<Fruit> createfruit(const string& name)
//     {
//         if(name=="apple")
//         {
//             //指针指针底层就是new了一个对象出来，shared_ptr智能指针可以被共享
//             //即可以被拷贝，作为返回值，即多个共享指针对象底层可以使用同一个new出来的对象
//             //有一个类中的静态成员（引用计数）表示new出来的对象被几个共享指针使用，
//             //当引用计数为0 时new出来的对象就会被释放。
//             return std::make_shared<Apple>();
//         }else{
//             return std::make_shared<Banana>();
//         }
//     }
// };


//定义一个水果工厂抽象类
// class FruitFactoy
// {
// public:
//     virtual std::shared_ptr<Fruit> creat()=0;
// };

//定义每个具体水果工厂派生类继承工厂类然后重写方法
//这样只要一种水果对应着一个工厂就不用在工厂类中添加方法
//只需添加工厂就行了,但是一旦类多了起来就不太好维护了
// class AppleFactory:public FruitFactoy
// {
// public:
//   std::shared_ptr<Fruit> creat() override
//   {
//         return std::make_shared<Apple>();
//   }  
// };

// class BananaFactory:public FruitFactoy
// {
// public:
//   std::shared_ptr<Fruit> creat() override
//   {
//         return std::make_shared<Banana>();
//   }  
// };


//方法3 定义一个总工厂的抽象类提供每个类的工厂方法，让不同产品类的工厂继承方法重写
class Factory
{
public:
    virtual std::shared_ptr<Fruit> GetFruit(const string& name)=0;
    virtual std::shared_ptr<Animal> GetAnimal(const string& name)=0;
};

//定义具体的工厂类继承总工厂的抽象方法然后重写
class FruitFactory:public Factory
{
public:
    virtual std::shared_ptr<Fruit> GetFruit(const string& name)
    {
        if(name=="apple")
        {
            return std::make_shared<Apple>();

        }else{
            return std::make_shared<Banana>();
        }
    }
    virtual std::shared_ptr<Animal> GetAnimal(const string& name)
    {
        return std::shared_ptr<Animal>();
    }
};

class AnimalFactory:public Factory
{
public:
    virtual std::shared_ptr<Animal> GetAnimal(const string& name)
    {
        if(name=="lamp")
        {
            return std::make_shared<Lamp>();

        }else{
            return std::make_shared<Dog>();
        }
    }
    virtual std::shared_ptr<Fruit> GetFruit(const string& name)
    {
        return std::shared_ptr<Fruit>();
    }
};

//提供一个具体的工厂类的生产方法
class FactoryProducer
{
public:
    static shared_ptr<Factory> create(const string& name)
    {
        if(name=="水果")
        {
            //生产水果类工厂
            return make_shared<FruitFactory>();
        }else 
        {
            return make_shared<AnimalFactory>();
        }
    }


};
int main()
{
    // std::unique_ptr<FruitFactoy> FC=std::make_unique<FruitFactoy>();

    // shared_ptr<Fruit> f1=FC->createfruit("apple");
    // f1->name();
    // //同一个方法生产不同类型的产品
    // shared_ptr<Fruit> f2=FC->createfruit("bananl");
    //f2->name();

    //定义一个苹果工厂类用工厂类基类指针接收
    // std::shared_ptr<FruitFactoy> FC=std::make_shared<AppleFactory>();
    // shared_ptr<Fruit> f1=FC->creat();
    // f1->name();
    // FC=std::make_shared<BananaFactory>();
    // f1=FC->creat();
    // f1->name();

    //定义一个总工厂基类指针来接收派生类工厂
    shared_ptr<Factory> Fac=FactoryProducer::create("水果");
    //水果类工厂生产具体的水果
    shared_ptr<Fruit> f1=Fac->GetFruit("apple");
    f1->name();
    f1=Fac->GetFruit("banana");
    f1->name();
    //生产动物类工厂
    Fac=FactoryProducer::create("动物");
    //生产具体的动物
    shared_ptr<Animal> d1=Fac->GetAnimal("lamp");
    d1->name();
    d1=Fac->GetAnimal("dog");
    d1->name();
}